package com.tencent.sr.iris.activity.restapi.tools;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tencent.sr.iris.activity.common.config.DynamicConfig;
import com.tencent.sr.iris.activity.common.config.IrisThreadPoolConfig;
import com.tencent.sr.iris.activity.dependency.dto.data.CommissionInfoDTO;
import com.tencent.sr.iris.activity.dependency.qufa.GroupTaskDependency;
import com.tencent.sr.iris.activity.dependency.user.UserCoreDependency;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityCheckResultDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.interfaces.AdminOperateRequest;
import com.tencent.sr.iris.activity.interfaces.client.tool.IrisActivityToolClient;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityEventSourceEnum;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityEventTypeEnum;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.interfaces.request.IrisPaginationRequest;
import com.tencent.sr.iris.activity.interfaces.request.acticity.*;
import com.tencent.sr.iris.activity.interfaces.request.task.*;
import com.tencent.sr.iris.activity.interfaces.response.InviteDataFreshResponse;
import com.tencent.sr.iris.activity.interfaces.response.activity.EventHandingRecordResponse;
import com.tencent.sr.iris.activity.interfaces.response.activity.UserAwardRetryResponse;
import com.tencent.sr.iris.activity.interfaces.response.activity.UserTaskRecordResponse;
import com.tencent.sr.iris.activity.service.activity.*;
import com.tencent.sr.iris.activity.service.activity.impl.DataRefreshService;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.config.ResponseMockConfig;
import com.tencent.sr.iris.activity.service.event.activity.UserBecomeTraineeActivityExecutor;
import com.tencent.sr.iris.activity.service.event.job.ActivityTaskEventRetryJob;
import com.tencent.sr.iris.activity.service.event.job.UserActivityTaskRecordStatusFixJob;
import com.tencent.sr.iris.activity.service.event.job.UserAwardRetryJob;
import com.tencent.sr.iris.activity.service.event.task.UserBecomeTraineeTaskExecutor;
import com.tencent.sr.iris.activity.service.event.util.ActivityCommonUtilService;
import com.tencent.sr.iris.activity.service.task.InviteDataFreshTaskService;
import com.tencent.sr.iris.activity.service.util.IdCreateorUtil;
import com.tencent.sr.iris.basic.service.interfaces.client.RainbowClient;
import com.tencent.sr.iris.basic.service.interfaces.constant.EnvEnum;
import com.tencent.sr.iris.basic.service.interfaces.constant.RainbowValueTypeEnum;
import com.tencent.sr.iris.basic.service.interfaces.request.UpdateRainbowRequest;
import com.tencent.sr.iris.basic.service.interfaces.response.UpdateRainbowResponse;
import com.tencent.sr.iris.user.core.service.interfaces.enums.UserLevelEnum;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.SupervisorRelationResponse;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import com.tencent.sr.rmall.common.exception.retail.TRetailErrorException;
import com.tencent.sr.rmall.common.primitive.HttpResult;
import com.tencent.sr.rmall.common.request.PaginationRequest;
import com.tencent.sr.rmall.common.response.PaginationResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 描述用途
 *
 * @author wruiiwang
 * @date 2023/2/19
 */
@Slf4j
@Api(tags = "工具平台接口", value = "工具平台接口")
@RestController
@RequestMapping(value = {"/api/v1/iris/iris-activity-core-service/activity/tool"})
public class ToolController implements IrisActivityToolClient {


    @Resource
    private DynamicConfig dynamicConfig;
    @Resource
    private UserAwardRetryJob userAwardRetryJob;
    @Resource
    private ActivityTaskEventRetryJob activityTaskEventRetryJob;

    @Resource
    private UserActivityTaskRecordStatusFixJob userActivityTaskRecordStatusFixJob;
    @Resource
    private IrisUserTaskRecordService userTaskRecordService;
    @Resource
    private RainbowClient rainbowClient;
    @Resource
    private ResponseMockConfig responseMockConfig;
    @Resource
    private ActivityCommonService activityCommonService;
    @Resource
    private ActivityCommonUtilService activityCommonUtilService;
    @Resource
    private IdCreateorUtil idCreateorUtil;
    @Resource
    private AwardMonitorService awardMonitorService;
    @Resource
    private InviteDataFreshTaskService inviteDataFreshTaskService;
    @Resource
    private IrisEventHandingRecordService irisEventHandingRecordService;

    @Resource
    private DataRefreshService dataRefreshService;


    @PostMapping("mockTraineeTime")
    @Override
    public HttpResult<String> mockTraineeTime(@RequestBody @Validated MockTraineeTimeRequest request) {

        if (Strings.isNullOrEmpty(request.getTraineeTime())) {
            responseMockConfig.getTraineeTimeResultMock().remove(request.getUid());
        } else {
            responseMockConfig.getTraineeTimeResultMock().put(request.getUid(), request.getTraineeTime());
        }
        return updateMockDataKey();
    }

    @PostMapping("mockCommission")
    @Override
    public HttpResult<String> mockCommission(@RequestBody @Validated MockCommissionRequest request) {

        if (request.getMockCommissionDTO() == null) {
            responseMockConfig.getCommissionResultMock().remove(request.getUid());
        } else {
            CommissionInfoDTO commissionInfoDTO = new CommissionInfoDTO();
            BeanUtils.copyProperties(request.getMockCommissionDTO(), commissionInfoDTO);
            responseMockConfig.getCommissionResultMock().put(request.getUid(), commissionInfoDTO);
        }
        return updateMockDataKey();
    }

    private HttpResult<String> updateMockDataKey() {
        String value = JSON.toJSONString(responseMockConfig);
        UpdateRainbowRequest updateRequest = new UpdateRainbowRequest();
        updateRequest.setGroup("default.iris-activity-core-service");
        updateRequest.setDescription("工具平台mockTraineeTime");
        ArrayList<String> envList = Lists.newArrayList();
        if (EnvEnum.ENV_QA.getCode().equals(dynamicConfig.getEnv())) {
            envList.add(EnvEnum.ENV_QA.getCode());
        } else {
            envList.add(EnvEnum.ENV_ONLINE.getCode());
            envList.add(EnvEnum.ENV_ONLINE.getCode());
        }
        updateRequest.setEnvList(envList);
        updateRequest.setKey("responseMockConfig");
        updateRequest.setOperator("工具平台");
        updateRequest.setValue(value);
        updateRequest.setValueType(RainbowValueTypeEnum.JSON.getCode());
        HttpResult<UpdateRainbowResponse> res = rainbowClient.updateRainbowKV(
                updateRequest);
        if (!res.isSuccess() || res.getData() == null) {
            return HttpResult.fail("更新七彩石异常,result:" + JSON.toJSONString(res));
        }
        return HttpResult.succ("更新七彩石成功");
    }

    @PostMapping("mockEvent")
    @Override
    public HttpResult<String> mockEvent(@RequestBody @Validated MockEventRequest request) {
        return HttpResult.succ("");
    }

    @PostMapping("queryTraineeTime")
    @Override
    public HttpResult queryTraineeTime(@RequestBody @Validated UserBaseRequest request) {
        Long traineeTime = activityCommonService.queryTraineeTime(request.getUid());
        return HttpResult.succ(ImmutableMap.of("traineeTime", traineeTime == null ? 0L : traineeTime));
    }

    @PostMapping("queryUserTaskRecordPage")
    @Override
    public HttpResult<PaginationResponse<UserTaskRecordResponse>> queryUserTaskRecordPage(
            @RequestBody @Validated PaginationRequest<QueryUserTaskRecordPageRequest> request) {

        PaginationResponse<UserTaskRecordResponse> response = userTaskRecordService.userTaskPageDb(request);
        return HttpResult.succ(response);
    }

    @PostMapping("queryEventHandingInfoPage")
    @Override
    public HttpResult<PaginationResponse<EventHandingRecordResponse>> queryEventHandingInfoPage(
            @RequestBody @Validated PaginationRequest<QueryEventHandingRecordPageRequest> request) {
        PaginationResponse<EventHandingRecordResponse> response = irisEventHandingRecordService.queryEventHandingInfoPage(request);
        return HttpResult.succ(response);
    }

    @PostMapping("updateUserTaskRecord")
    @Override
    public HttpResult<Boolean> updateUserTaskRecord(@RequestBody @Validated UpdateUserTaskRecordRequest request) {

        Boolean res = userTaskRecordService.updateUserTaskRecord(request);
        return HttpResult.succ(res);
    }

    @PostMapping("userAwardRetry")
    @ApiOperation(value = "userAwardRetry", httpMethod = "POST")
    @Override
    public HttpResult<UserAwardRetryResponse> userAwardRetry(
            @Validated @RequestBody UserAwardRetryRequest request) {

        List<String> uidList = request.getUidList();
        if (!request.getRetryAll() && CollectionUtil.isEmpty(uidList)) {
            throw new TRetailBizException("非全量重试，uidList不能为空");
        }

        if (request.getRetryAll()) {
            userAwardRetryJob.execute(null);
            return HttpResult.succ(null);
        }

        Map<String, Integer> map = Maps.newHashMap();
        for (String uid : uidList) {
            Integer count = userAwardRetryJob.doRetryByUid(uid);
            map.put(uid, count);
        }
        UserAwardRetryResponse res = new UserAwardRetryResponse();
        res.setUidRetryCount(map);
        return HttpResult.succ(res);
    }


    @PostMapping("eventRetry")
    @ApiOperation(value = "eventRetry", httpMethod = "POST")
    @Override
    public HttpResult<Boolean> eventRetry(@Validated @RequestBody EventRetryRequest request) {

        activityTaskEventRetryJob.execute(request);
        return HttpResult.succ(true);
    }



    @PostMapping("taskRecordRetry")
    @ApiOperation(value = "taskRecordRetry", httpMethod = "POST")
    @Override
    public HttpResult<Boolean> taskRecordRetry(@Validated @RequestBody TaskRecordRetryRequest request) {
        if (!request.getRetryAll() && Strings.isNullOrEmpty(request.getUid())) {
            throw new TRetailBizException("非全量重试，uid不能为空");
        }

        if (request.getRetryAll()) {
            userActivityTaskRecordStatusFixJob.execute(null);
            log.info("手动触发statusFixJob 全量执行，request:{}", JSON.toJSONString(request));
            return HttpResult.succ(true);
        }

        if (CollectionUtil.isNotEmpty(request.getTaskRecordBizIdList())) {
            for (String taskRecordBizId : request.getTaskRecordBizIdList()) {
                userActivityTaskRecordStatusFixJob.doExecuteUid(request.getUid(), taskRecordBizId);
                log.info("手动触发statusFixJob taskRecordBizId维度执行，request:{}", JSON.toJSONString(request));
            }
        } else {
            userActivityTaskRecordStatusFixJob.doExecuteUid(request.getUid(), null);
            log.info("手动触发statusFixJob taskRecordBizId维度执行，request:{}", JSON.toJSONString(request));
        }

        return HttpResult.succ(true);
    }



    @Resource
    private GroupTaskDependency groupTaskDependency;
    @Resource
    public ActivityConfig activityConfig;

    @Resource
    private IrisActivityService activityService;

    @Resource
    private UserBecomeTraineeActivityExecutor userBecomeTraineeActivityExecutor;
    @Resource
    private UserBecomeTraineeTaskExecutor userBecomeTraineeTaskExecutor;

    @Resource
    protected UserCoreDependency userCoreDependency;

    @Resource(name = IrisThreadPoolConfig.IRIS_FRESH_DATA_THREAD_EXECUTOR)
    private Executor irisPushAllUserBecomeTraineeThreadExecutor;


    /**
     * 同步业务影响范围，全量推的范围，
     * 从业务拿到应发的见习会员全量uid，通过这个数据集全量推送
     * 推送范围，补的券，
     * 发版节奏和推数节奏
     *
     * @param req
     * @return
     */
    @PostMapping("pushAllUserBecomeTrainee")
    @ApiOperation(value = "pushAllUserBecomeTrainee", httpMethod = "POST")
    public HttpResult<Map<String, String>> pushAllUserBecomeTrainee(@Validated @RequestBody AdminOperateRequest req) {

        log.info("pushAllUserBecomeTrainee start");
        Map<String, String> resultMap = Maps.newHashMap();
        final AtomicInteger totalCount = new AtomicInteger(0);
        final List<String> errorList = Lists.newCopyOnWriteArrayList();
        final List<String> bizFailList = Lists.newCopyOnWriteArrayList();
        try {

            //加载注册有礼活动和任务
            ActivityDTO act = activityService.getActivityAllTask(activityConfig.getRegistGiftActivityId());

            if (!CollectionUtils.isEmpty(req.getUidList())) {
                for (String uid : req.getUidList()) {
                    executeOneUser(act, uid, totalCount, bizFailList, errorList, null);
                    resultMap.put("totalCount", String.valueOf(req.getUidList().size()));
                }
                resultMap.put("bizFailCount", String.valueOf(bizFailList.size()));
                resultMap.put("errorCount", String.valueOf(errorList.size()));
                log.info("pushAllUserBecomeTrainee end, result:{}", JSON.toJSONString(resultMap));
                return HttpResult.succ(resultMap);
            }

            final List<String> uids = Lists.newArrayList();
            if (!Strings.isNullOrEmpty(req.getLocalPath())) {
                EasyExcel.read(req.getLocalPath(), ExcelData.class,
                        new UpdateListener(uids))
                        .sheet().doRead();
            }

            CountDownLatch latch = new CountDownLatch(uids.size() - req.getStartIndex());
            for (int i = req.getStartIndex(); i < uids.size(); i++) {
                String uid = uids.get(i);
                //停止刷数
                if (activityConfig.isStopPushAllUserBecomeTrainee()) {
                    log.info("pushAllUserBecomeTrainee stop, totalCount:{},bizFailCount:{},errorCount:{}", totalCount,
                            bizFailList.size(), errorList.size());
                    resultMap.put("totalCount", String.valueOf(totalCount));
                    resultMap.put("bizFailCount", String.valueOf(bizFailList.size()));
                    resultMap.put("errorCount", String.valueOf(errorList.size()));
                    return HttpResult.succ(resultMap);
                }

                CompletableFuture<Void> features = CompletableFuture.runAsync(
                        () -> executeOneUser(act, uid, totalCount, bizFailList, errorList, latch),
                        irisPushAllUserBecomeTraineeThreadExecutor);
                log.info("pushAllUserBecomeTrainee processing, totalCount:{},bizFailCount:{},errorCount:{}", totalCount,
                        bizFailList.size(), errorList.size());


            }
            latch.await();
            resultMap.put("totalCount", String.valueOf(totalCount));
            resultMap.put("bizFailCount", String.valueOf(bizFailList.size()));
            resultMap.put("errorCount", String.valueOf(errorList.size()));
            resultMap.put("bizFailList", JSON.toJSONString(bizFailList));
            resultMap.put("errorList", JSON.toJSONString(errorList));

        } catch (Exception e) {
            log.error("pushAllUserBecomeTrainee:执行异常,totalCount:{},bizFailCount:{},errorCount:{}", totalCount,
                    bizFailList.size(), errorList.size(), e);
        }
        log.info("pushAllUserBecomeTrainee end, request:{},response:{}", JSON.toJSONString(req),
                JSON.toJSONString(resultMap));
        return HttpResult.succ(resultMap);
    }


    private void executeOneUser(ActivityDTO act, String uid, AtomicInteger totalCount, List<String> bizFailList,
            List<String> errorList, CountDownLatch latch) {

        try {
            totalCount.incrementAndGet();
            //校验用户是见习会员
            boolean isTrainee = activityCommonUtilService.isUserLevelIn(uid,
                    Lists.newArrayList(UserLevelEnum.TRAINEE.getValue()));
            if (!isTrainee) {
                throw new TRetailBizException("用户不是见习会员");
            }

            //组装事件实体
            ActivityEventDTO eventDTO = new ActivityEventDTO();
            eventDTO.setUid(uid);
            eventDTO.setPid(null);
            eventDTO.setEventType(ActivityEventTypeEnum.BECOME_TRAINEE.getCode());
            Map<String, String> map = Maps.newHashMap();
            map.put("uid", uid);
            map.put("afterLevelId", "TRAINEE");
            map.put("beforeLevelId", "FAN");
            long eventTime = System.currentTimeMillis();
            map.put("timeStamp", String.valueOf(eventTime));
            eventDTO.setEventInfo(JSON.toJSONString(map));
            eventDTO.setIdempotent("admin_operate_" + idCreateorUtil.genId());
            eventDTO.setEventSource(ActivityEventSourceEnum.ADMIN_OPERATE.getCode());
            eventDTO.setEventTime(eventTime);
            eventDTO.setCreateTime(eventTime);

            //补充pid
            addParameterForEvent(eventDTO);

            //4.活动准入规则校验
            ActivityCheckResultDTO activityCheckResultDTO = userBecomeTraineeActivityExecutor.doActivityCheck(
                    act, eventDTO);
            if (!activityCheckResultDTO.isSatisfy()) {
                throw new TRetailBizException(activityCheckResultDTO.getErrorMsg());
            }

            //调用任务处理器
            userBecomeTraineeTaskExecutor.execute(eventDTO, act, act.getActivityTaskDTOS().get(0), null);
            log.info("admin_operate success, uid:{}, totalCount:{},failCount:{},errorCount:{}", uid, totalCount,
                    bizFailList.size(), errorList.size());
        } catch (TRetailBizException e) {
            bizFailList.add(uid);
            log.error(
                    "admin_operate user check bizFail,uid:{}, totalCount:{},failCount:{},errorCount:{}, msg:{}",
                    uid, totalCount, bizFailList.size(), errorList.size(), e.getMessage());
        } catch (Exception e) {
            errorList.add(uid);
            log.error("admin_operate error,uid:{}, totalCount:{},failCount:{},errorCount:{}, uid:{}", uid,
                    totalCount,
                    bizFailList.size(), errorList.size(),
                    e);
        } finally {
            if (latch != null) {
                latch.countDown();
            }

        }


    }

    protected void addParameterForEvent(ActivityEventDTO eventDTO) {
        //补充pid
        try {
            SupervisorRelationResponse response = userCoreDependency
                    .queryUserSupervisor(eventDTO.getUid());
            if (Objects.nonNull(response) && !StringUtils.isEmpty(response.getParentUid())) {
                eventDTO.setPid(response.getParentUid());
            }
        } catch (Exception e) {
            log.info("查询上级pid失败，uid:{}", eventDTO.getUid());
            throw new TRetailErrorException("事件补充用户PID失败");
        }
    }

    @PostMapping("updateTaskRecordPid")
    @ApiOperation(value = "补刷pid", httpMethod = "POST")
    public HttpResult<List<String>> updateTaskRecordPid(@RequestBody JSONObject req) {
        Integer pageSize = Optional.ofNullable(req.getInteger("pageSize")).orElse(50);
        List<String> taskRecordIds = userTaskRecordService.updateTaskRecordPid(pageSize);
        return HttpResult.succ(taskRecordIds);
    }

    @PostMapping("updateTaskRecordGmv")
    @ApiOperation(value = "补刷gmv", httpMethod = "POST")
    public HttpResult<Boolean> updateTaskRecordGmv(@RequestBody JSONObject req) {
        Integer pageSize = Optional.ofNullable(req.getInteger("pageSize")).orElse(50);
        Integer shardingId = req.getInteger("shardingId");
        boolean success = userTaskRecordService.updateTaskRecordGmv(pageSize, shardingId);
        return HttpResult.succ(success);
    }

    @PostMapping("startAwardMonitorConsumer")
    @ApiOperation(value = "开启资损监控", httpMethod = "POST")
    public HttpResult<Boolean> startAwardMonitorConsumer() {
        awardMonitorService.startConsumer();
        return HttpResult.succ(true);
    }

    @PostMapping("queryInviteAwardUidList")
    @ApiOperation(value = "queryInviteAwardUidList", httpMethod = "POST")
    public HttpResult<InviteDataFreshResponse> queryInviteAwardUidList(@RequestBody InviteDataFreshRequest request) {
        InviteDataFreshResponse result = inviteDataFreshTaskService.queryAwardUidList(request);
        log.info("queryInviteAwardUidList result:{}",result);
        return HttpResult.succ(result);
    }

    @PostMapping("inviteAwardDeal")
    @ApiOperation(value = "inviteAwardDeal", httpMethod = "POST")
    public HttpResult<InviteDataFreshResponse> inviteAwardDeal(@RequestBody InviteDataFreshRequest request) {
        InviteDataFreshResponse result = inviteDataFreshTaskService.inviteAwardDeal(request);
        log.info("inviteAwardDeal result:{}",result);
        return HttpResult.succ(result);
    }

    @PostMapping("inviteTaskStatusDeal")
    @ApiOperation(value = "inviteTaskStatusDeal", httpMethod = "POST")
    public HttpResult<InviteDataFreshResponse> inviteTaskStatusDeal(@RequestBody InviteDataFreshRequest request) {
        InviteDataFreshResponse result = inviteDataFreshTaskService.inviteTaskStatusDeal(request);
        log.info("inviteTaskStatusDeal result:{}",result);
        return HttpResult.succ(result);
    }

    @PostMapping("queryLimitPid")
    @ApiOperation(value = "queryLimitPid", httpMethod = "POST")
    public HttpResult<InviteDataFreshResponse> queryLimitPid(@RequestBody InviteDataFreshRequest request) {
        InviteDataFreshResponse result = inviteDataFreshTaskService.queryLimitPid(request);
        log.info("queryLimitPid result:{}",result);
        return HttpResult.succ(result);
    }

    @PostMapping("updateUserIsParticipated")
    @ApiOperation(value = "updateUserIsParticipated", httpMethod = "POST")
    public HttpResult<InviteDataFreshResponse> updateUserIsParticipated(@RequestBody InviteDataFreshRequest request) {
        InviteDataFreshResponse result = inviteDataFreshTaskService.updateUserIsParticipated(request);
        log.info("updateUserIsParticipated result:{}",result);
        return HttpResult.succ(result);
    }

    @PostMapping("addOrUpdateActivityRecords")
    @ApiOperation(value = "addOrUpdateActivityRecords", httpMethod = "POST")
    public HttpResult<Boolean> addOrUpdateActivityRecords(
            @RequestBody @Validated IrisPaginationRequest<FreshActivityRecordRequest> request) {
        dataRefreshService.addOrUpdateActivityRecords(request);
        return HttpResult.succ(true);
    }

    @PostMapping("refreshSendAward")
    @ApiOperation(value = "refreshSendAward", httpMethod = "POST")
    public HttpResult<Boolean> refreshSendAward(
            @RequestBody @Validated IrisPaginationRequest<FreshActivityRecordRequest> request) {
        dataRefreshService.refreshSendAward(request);
        return HttpResult.succ(true);
    }
}

